import React, {Component} from 'react';
import {
  View
} from 'react-native';
import PropTypes from 'prop-types';
import ViewPropTypes from 'deprecated-react-native-prop-types'
import XDate from '../xdate';
import dateutils from '../dateutils';
import {xdateToData, parseDate} from '../interface';
import styleConstructor from './style';
import Day from './day/basic/index';
import UnitDay from './day/period/index';
import MultiDotDay from './day/multi-dot/index';
import CalendarHeader from './header/index';
import CalendarWeekHeader from './header/CalendarWeekHeader';
import shouldComponentUpdate from './updater';

const viewPropTypes = ViewPropTypes || View.propTypes;

const EmptyArray = [];

class Calendar extends Component {
  static propTypes = {
    // Specify theme properties to override specific styles for calendar parts. Default = {}
    theme: PropTypes.object,
    // Collection of dates that have to be marked. Default = {}
    markedDates: PropTypes.object,
    // 需要增加班次性质的日期。 Default = {}
    workShiftDates: PropTypes.object,
    // Specify style for calendar container element. Default = {}
    style: viewPropTypes.style,
    // Initially visible month. Default = Date()
    current: PropTypes.any,
    // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
    minDate: PropTypes.any,
    // Maximum date that can be selected, dates after maxDate will be grayed out. Default = undefined
    maxDate: PropTypes.any,

    // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
    firstDay: PropTypes.number,

    // Date marking style [simple/period]. Default = 'simple'
    markingType: PropTypes.string,

    // Hide month navigation arrows. Default = false
    hideArrows: PropTypes.bool,
    // Display loading indicador. Default = false
    displayLoadingIndicator: PropTypes.bool,
    // Do not show days of other months in month page. Default = false
    hideExtraDays: PropTypes.bool,

    // Handler which gets executed on day press. Default = undefined
    onDayPress: PropTypes.func,
    // Handler which gets executed when visible month changes in calendar. Default = undefined
    onMonthChange: PropTypes.func,
    onVisibleMonthsChange: PropTypes.func,
    // Replace default arrows with custom ones (direction can be 'left' or 'right')
    renderArrow: PropTypes.func,
    // Provide custom day rendering component
    dayComponent: PropTypes.any,
    // Month format in calendar title. Formatting values: http://arshaw.com/xdate/#Formatting
    monthFormat: PropTypes.string,
    // Disables changing month when click on days of other months (when hideExtraDays is false). Default = false
    disableMonthChange: PropTypes.bool,
    //  Hide day names. Default = false
    hideDayNames: PropTypes.bool,
    // Disable days by default. Default = false
    disabledByDefault: PropTypes.bool,
    // Show week numbers. Default = false
    showWeekNumbers: PropTypes.bool,
    isMonthView : PropTypes.bool,
    //周末是否颜色突出
    weekendsObv : PropTypes.bool,
    //隐藏月/周视图转换开关
    hideViewToggle: PropTypes.bool,
  };

  constructor(props) {
    super(props);
    this.style = styleConstructor(this.props.theme);
    let currentMonth;
    if (props.current) {
      currentMonth = parseDate(props.current);
    } else {
      currentMonth = XDate();
    }
    this.state = {
      prevPropsCurrent: currentMonth,
      currentMonth,
      renderMonthView: this.props.isMonthView,
      activeWeek : 1,
      weeksLength : 0
    };

    this.updateMonth = this.updateMonth.bind(this);
    this.addMonth = this.addMonth.bind(this);
    this.pressDay = this.pressDay.bind(this);
    this.shouldComponentUpdate = shouldComponentUpdate;
  }

  // componentWillMount(){
  //     let tempWeek = this.getWeekForCurrentMonth()
  //     let tempWeeksLength = this.getWeeks().length
  //     this.setState({
  //         weeksLength : tempWeeksLength,
  //         activeWeek : tempWeek,
  //     });
  // }

  componentDidMount(){
    let tempWeek = this.getWeekForCurrentMonth()
    let tempWeeksLength = this.getWeeks().length
    this.setState({
        weeksLength : tempWeeksLength,
        activeWeek : tempWeek,
    });
}

  // componentWillReceiveProps(nextProps) {
  //   const current= parseDate(nextProps.current);
  //   console.log(this.state.currentMonth.toString('yyyy MM dd'))
  //   console.log(current.toString('yyyy MM dd'))
  //   if (current && current.toString('yyyy MM dd') !== this.state.currentMonth.toString('yyyy MM dd')) {
  //     this.setState({
  //       currentMonth: current.clone()
  //     });
  //   }
  // }

  static getDerivedStateFromProps(nextProps, prevState) {
    const current= parseDate(nextProps.current);
    if (current && current.toString('yyyy MM dd') !== prevState.prevPropsCurrent.toString('yyyy MM dd')) {
        return {
          prevPropsCurrent: current.clone(),
          currentMonth: current.clone()
        };
    }
    return null;
  }

  updateMonth(day, doNotTriggerListeners) {
    if (day.toString('yyyy MM') === this.state.currentMonth.toString('yyyy MM')) {
      return;
    }
    this.setState({
      currentMonth: day.clone()
    }, () => {
      if (!doNotTriggerListeners) {
        const currMont = this.state.currentMonth.clone();
        if (this.props.onMonthChange) {
          this.props.onMonthChange(xdateToData(currMont));
        }
        if (this.props.onVisibleMonthsChange) {
          this.props.onVisibleMonthsChange([xdateToData(currMont)]);
        }
      }
    });
  }

  pressDay(date) {
    const day = parseDate(date);
    const minDate = parseDate(this.props.minDate);
    const maxDate = parseDate(this.props.maxDate);
    if (!(minDate && !dateutils.isGTE(day, minDate)) && !(maxDate && !dateutils.isLTE(day, maxDate))) {
      const shouldUpdateMonth = this.props.disableMonthChange === undefined || !this.props.disableMonthChange;
      if (shouldUpdateMonth) {
        this.updateMonth(day);
      }
      if (this.props.onDayPress) {
        this.props.onDayPress(xdateToData(day));
      }
    }
  }

  addMonth(count) {

    if(typeof this.props.unhidenBackground == 'function' && this.props.unhidenBackground){
      this.props.unhidenBackground()   
  }

    this.updateMonth(this.state.currentMonth.clone().addMonths(count, true));
  }

  addWeek = () => {
      if (this.state.activeWeek < this.state.weeksLength) {
          this.setState({
              activeWeek: this.state.activeWeek + 1
          })
      } else if (this.state.activeWeek = this.state.weeksLength) {
          this.addMonth(1)
          let tempWeeksLength = this.getWeeks().length
          this.setState({
              weeksLength : tempWeeksLength,
              activeWeek : 1,
          });
      }
  }

    substractWeek = () => {
        if (this.state.activeWeek > 1) {
            this.setState({
                activeWeek: this.state.activeWeek - 1
            })
        } else if (this.state.activeWeek = 1) {
            this.addMonth(-1)
            let tempWeeksLength = this.getWeeks().length
            this.setState({
                weeksLength : tempWeeksLength,
                activeWeek : 1,
            });
        }
    }



  translateView = ()=>{
    let tempWeek = this.getWeekForCurrentMonth()
    let tempWeeksLength = this.getWeeks().length
      this.setState({
          weeksLength : tempWeeksLength,
          activeWeek : tempWeek,
          renderMonthView : !this.state.renderMonthView
      });
  }

  getWeeks = () =>{
      const days = dateutils.page(this.state.currentMonth, this.props.firstDay);
      const weeks = [];
      while (days.length) {
          weeks.push(this.renderWeek(days.splice(0, 7), weeks.length));
      }

      return weeks
  }

  getWeekForCurrentMonth = () =>{
      //计算当前日期在本月的第几周，用于单行显示周视图
      let firstDayOfCurrentMonth = dateutils.month(this.state.currentMonth)[0];
      let dayNameFirst = firstDayOfCurrentMonth.getDay(); //每月第一天是星期几，0代表周日，1代表周一
      let currentDay = parseDate(this.state.currentMonth).getDate();
      currentDay += dayNameFirst;
      let weekForCurrentMonth;  //当前日期在本月的第几周
      if (currentDay%7 === 0) {
          weekForCurrentMonth = Math.floor(currentDay/7);
      } else if (currentDay%7 > 0) {
          weekForCurrentMonth = Math.floor(currentDay/7) + 1;
      }
      return weekForCurrentMonth
  }

  renderDay(day, id) {
    //增加周末变色功能
    let whatDay = day.getDay();
    const minDate = parseDate(this.props.minDate);
    const maxDate = parseDate(this.props.maxDate);
    let state = '';
    if (this.props.disabledByDefault) {
      state = 'disabled';
    } else if ((minDate && !dateutils.isGTE(day, minDate)) || (maxDate && !dateutils.isLTE(day, maxDate))) {
      state = 'disabled';
    } else if (!dateutils.sameMonth(day, this.state.currentMonth)) {
      state = 'disabled';
    } else if (dateutils.sameDate(day, XDate())) {
      state = 'today';
    } else if (this.props.weekendsObv){
        if (whatDay === 0 || whatDay ===6){
            state = 'weekends';
        }
    }
    let dayComp;
    if (!dateutils.sameMonth(day, this.state.currentMonth) && this.props.hideExtraDays) {
      if (this.props.markingType === 'period') {
        dayComp = (<View key={id} style={{flex: 1}}/>);
      } else {
        dayComp = (<View key={id} style={{width: 32}}/>);
      }
    } else {
      const DayComp = this.getDayComponent();
      const date = day.getDate();
      dayComp = (
        <DayComp
        key={id}
        state={state}
        theme={this.props.theme}
        onPress={this.pressDay}
        date={xdateToData(day)}
        marking={this.getDateMarking(day)}
        workShift={this.getDateWorkShift(day)}
    >
        {date}
    </DayComp>
      );
    }
    return dayComp;
  }

  getDayComponent() {
    if (this.props.dayComponent) {
      return this.props.dayComponent;
    }

    switch (this.props.markingType) {
    case 'period':
      return UnitDay;
    case 'multi-dot':
      return MultiDotDay;
    default:
      return Day;
    }
  }

  getDateMarking(day) {
    if (!this.props.markedDates) {
      return false;
    }
    const dates = this.props.markedDates[day.toString('yyyy-MM-dd')] || EmptyArray;
    if (dates.length || dates) {
      return dates;
    } else {
      return false;
    }
  }

    getDateWorkShift(day) {
        if (!this.props.workShiftDates) {
            return false;
        }
        const dates = this.props.workShiftDates[day.toString('yyyy-MM-dd')] || EmptyArray;
        if (dates.length || dates) {
            return dates;
        } else {
            return false;
        }
    }

  renderWeekNumber (weekNumber) {
    return (<Day key={'week-'+weekNumber} theme={this.props.theme} state='disabled'>{weekNumber}</Day>);
  }

  renderWeek(days, id) {

    const week = [];
    days.forEach((day, id2) => {
      week.push(this.renderDay(day, id2));
    }, this);

    if (this.props.showWeekNumbers) {
      week.unshift(this.renderWeekNumber(days[days.length - 1].getWeek()));
    }

    return (<View style={this.style.week} key={id}>{week}</View>);
  }



    render() {
        let weeks = this.getWeeks()
        //let indicator;
        // const current = parseDate(this.props.current);
        // if (current) {
        //     const lastMonthOfDay = current.clone().addMonths(1, true).setDate(1).addDays(-1).toString('yyyy-MM-dd');
        //     if (this.props.displayLoadingIndicator &&
        //         !(this.props.markedDates && this.props.markedDates[lastMonthOfDay])) {
        //         indicator = true;
        //     }
        // }

        let renderMonthContent = (
                    <View style={[this.style.container, this.props.style]}>
                    <CalendarHeader
                        theme={this.props.theme}
                        hideArrows={this.props.hideArrows}
                        month={this.state.currentMonth}
                        addMonth={this.addMonth}
                        translateView={this.translateView}
                        //showIndicator={indicator}
                        firstay={this.props.firstDay}
                        renderArrow={this.props.renderArrow}
                        monthFormat={this.props.monthFormat}
                        hideDayNames={this.props.hideDayNames}
                        weekNumbers={this.props.showWeekNumbers}
                        hideViewToggle={this.props.hideViewToggle}
                        weekendsObv={this.props.weekendsObv}
                    />
                        {weeks}
                    </View>
        )

        let renderWeekContent = (
                <View style={[this.style.container, this.props.style]}>
                    <CalendarWeekHeader
                        theme={this.props.theme}
                        hideArrows={this.props.hideArrows}
                        month={this.state.currentMonth}
                        addMonth={this.addMonth}
                        translateView={this.translateView}
                        addWeek={this.addWeek}
                        substractWeek={this.substractWeek}
                        //showIndicator={indicator}
                        firstay={this.props.firstDay}
                        renderArrow={this.props.renderArrow}
                        monthFormat={this.props.monthFormat}
                        hideDayNames={this.props.hideDayNames}
                        weekNumbers={this.props.showWeekNumbers}
                    />
                        {weeks[this.state.activeWeek-1]}
                </View>
            )

    return (
     this.state.renderMonthView ? renderMonthContent : renderWeekContent
    );
  }
}

Calendar.defaultProps = {
    isMonthView: true,
    weekendsObv: false,
    hideViewToggle: false
};

export default Calendar;
